package main

import (
	"context"
	"flag"
	"fmt"
	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
	grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	grpc_validator "github.com/grpc-ecosystem/go-grpc-middleware/validator"
	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
	"github.com/ifnk/own-blog/api/protobuf/user/v1"
	"github.com/ifnk/own-blog/internal/pkg/config"
	"github.com/ifnk/own-blog/internal/pkg/log"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"google.golang.org/grpc"
	"google.golang.org/grpc/health"
	"google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/reflection"
	"net"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

// 命令行可以 传 config.yaml 的路径 , 默认 的值的是  ./configs/config.yaml
var flagConfig = flag.String("config", "./configs/config.yaml", "path to config file")

// user 服务  启动器

func main() {
	flag.Parse()
	logger := log.New()
	// 加载 配置文件 config.yaml 获取 config 实体
	conf, err := config.Load(*flagConfig)
	if err != nil {
		logger.Fatal(err)
	}
	//logger.Infof("user 服务的 数据库连接字符串 dsn -> %+v", conf.User.DB.DSN)
	//
	userServer, _ := InitServer(logger, conf)
	if err != nil {
		logger.Fatal(err)
	}

	healthServer := health.NewServer()

	// 监控 指标
	// grpc_middleware  gRPC Go最近获得了对拦截器的支持，即在请求被传递到用户的应用程序逻辑之前在 gRPC 服务器上执行的中间件 ，或者在用户调用周围的 gRPC 客户端上执行的中间件。这是实现常见模式的完美方式：身份验证、日志记录、消息、验证、重试或监控。
	grpcServer := grpc.NewServer(grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
		grpc_prometheus.UnaryServerInterceptor, // 导入 grpc 版的 prometheus 服务
		grpc_validator.UnaryServerInterceptor(),
		grpc_recovery.UnaryServerInterceptor(), // 返回一个新的一元服务器拦截器用于紧急恢复
	)))

	v1.RegisterUserServiceServer(grpcServer, userServer)

	// 注册 grpc 反射服务   Server 端添加后可以通过该服务获取所有服务的信息，包括服务定义，方法，属性等
	reflection.Register(grpcServer)

	grpc_health_v1.RegisterHealthServer(grpcServer, healthServer)

	// 监听 user 服务 grpc 端口 50051
	lis, err := net.Listen("tcp", conf.User.Server.GRPC.Port)
	if err != nil {
		logger.Fatalf(" 监听 user 服务 grpc 端口 50051 失败  failed to listen: %v", err)
	}
	logger.Infof("监听 user 服务 grpc 端口   %s", conf.User.Server.GRPC.Port)

	// Start gRPC server
	ch := make(chan os.Signal, 1)
	go func() {
		if err = grpcServer.Serve(lis); err != nil {
			logger.Fatal(err)
		}
	}()

	// http 监听指标 路由是 /metrics
	logger.Infof("metrics 监听端口 on port %s", conf.User.Server.Metrics.Port)
	metricsMux := http.NewServeMux()
	metricsMux.Handle("/metrics", promhttp.Handler())
	metricsServer := &http.Server{
		Addr:    conf.User.Server.Metrics.Port,
		Handler: metricsMux,
	}
	go func() {
		if err = metricsServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			logger.Fatal(err)
		}
	}()

	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	<-ch
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	grpcServer.GracefulStop()
	if err = metricsServer.Shutdown(ctx); err != nil {
		logger.Fatal(err)
	}
	<-ctx.Done()
	close(ch)
	fmt.Println("Graceful Shutdown end")
}
